<?php
// $Id: BaseValue.abstract.php 73 2007-02-12 03:45:43Z tswicegood $

/**
 * This file contains {@link Item} which is part of the PHP Content Repository
 * (phpCR), a derivative of the Java Content Repository JSR-170,  and is 
 * licensed under the Apache License, Version 2.0.
 *
 * This file is based on the code created for
 * {@link http://www.jcp.org/en/jsr/detail?id=170 JSR-170}
 *
 * @author Travis Swicegood <travis@domain51.net>
 * @copyright PHP Code Copyright &copy; 2004-2005, Domain51, United States
 * @copyright Original Java and Documentation 
 *  Copyright &copy; 2002-2004, Day Management AG, Switerland
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, 
 *      Version 2.0
 * @package phpContentRepository
 */


/**
 * Load the {@link phpCR} library file(s)
 */ 
require_once(dirname(__FILE__) . '/phpCR.library.php');

phpCR::loadInterface('Value');
phpCR::loadClass('ValueStream');


/**
 * This class is the superclass of the type-specific classes implementing the 
 * {@link Value} interfaces.
 *
 * @see Value, StringValue, LongValue, IntValue, DoubleValue, FloatValue,
 *  DataValue, BinaryValue, SoftLinkValue, ReferenceValue
 * @author PHP - Travis Swicegood <travis@domain51.net>
 * @copyright Copyright &copy; 2004-2005, Domain51
 * @package phpContentRepository
 */
abstract class BaseValue implements Value 
{
   /**
    * The default encoding type for this {@link Value}
    *
    * @var string
    */
    const DEFAULT_ENCODING = "UTF-8";
    
    
   /**
    * The int representation of an undefined state.
    *
    * @var int
    */
    const STATE_UNDEFINED = 0;
    
    
   /**
    * The int representation of a consumed value.
    *
    * @var int
    */
    const STATE_VALUE_CONSUMED = 1;
    
    
   /**
    * The int representation of a consumed stream.
    *
    * @var int
    */
    const STATE_STREAM_CONSUMED = 2;
    
    
   /**
    * The current state of this {@link Value}.
    *
    * This should be the equivilent of one of the $STATE* values.
    *
    * @var int
    */
    private $state = self::STATE_UNDEFINED;
    
    
   /**
    * The current current type
    *
    * @var int
    */
    protected $type;
    
    
   /**
    * A resource for the current stream
    *
    * @var resource
    */
    protected $stream = null;
    
    
   /**
    * The raw data that this object represents
    *
    * @var mixed
    * @see getData()
    */
    protected $data = null;
    
    
   /**
    * Package-private default constructor.
    *
    * @param type The type of this value.
    */
    protected function __construct($type) {
        $this->type = $type;
    }
    
    
   /**
    * Checks if the non-stream value of this instance has already been
    * consumed (i.e. if any getter methods except {@link getStream()} and
    * {@link getType()} have been previously called at least once) and
    * sets the state to {@link $STATE_STREAM_CONSUMED}.
    *
    * @throws {@link IllegalStateException}
    *   If any getter methods other than {@link getStream()} and
    *   {@link getType()} have been previously called at least once.
    */
    protected function setStreamConsumed()
    {
        if ($this->state == self::STATE_VALUE_CONSUMED) {
            phpCR::loadException('IllegalState');
            throw new IllegalStateException("non-stream value has already been consumed");
        }
        
        $this->state = self::STATE_STREAM_CONSUMED;
    }
    
    
   /**
    * Checks if the stream value of this instance has already been
    * consumed (i.e. if {@link getStream()} has been previously called
    * at least once) and sets the state to {@link $STATE_VALUE_CONSUMED}.
    *
    * @throws {@link IllegalStateException} 
    *   If {@link getStream()} has been previously called at least once.
    */
    protected function setValueConsumed()
    {
        if ($this->state == self::STATE_STREAM_CONSUMED) {
            phpCR::loadException('IllegalState');
            throw new IllegalStateException("stream value has already been consumed");
        }
        
        $this->state = self::STATE_VALUE_CONSUMED;
    }

    
   /**
    * Returns the raw, unencapsulated value that this object represents.
    *
    * <b>PHP Note</b>: This has been added to the JCR implementation.  There
    * is no "equals()" method inside PHP to provide a comparsion between 
    * objects' private properties, thus we need a way to access the raw data
    * this object encapsulates.
    *
    * Unlike the other get*() methods, this does not expire the value/stream.
    *
    * @see BaseValue::raw()
    *
    * @return bool
    */
    public function getData()
    {
        return $this->data;
    }

   /**
    * @see Value::getType()
    */
    public function getType()
    {
        return $this->type;
    }
    
    
   /**
    * @see Value::getDouble()
    */
    public function getDouble()
    {
        return $this->getFloat();
    }
    
    
   /**
    * @see Value::getLong()
    */
    public function getLong()
    {
        return $this->getInt();
    }
    
   /**
    * @see Value::getDate()
    */
    public function getDate() 
    {
        $this->setValueConsumed();
        
        if (!is_null($this->data)) {
            return date(intval($this->data), 'c');
        } else {
            phpCR::loadException('ValueFormat');
            throw new ValueFormatException('empty value');
        }
    }
    
    
   /**
    * @see Value::getInt()
    */
    public function getInt()
    {
        $this->setValueConsumed();
    
        if (!is_null($this->data)) {
            switch (gettype($this->data)) {
            case 'array' :
            case 'object' :
                phpCR::loadException('ValueFormat');
                throw new ValueFormatException('conversion to int failed');
                break;
            
            default :
                return intval($this->data);
                break;
            }
        } else {
            phpCR::loadException('ValueFormat');
            throw new ValueFormatException('empty value');
        }
    }
    
    
    
    
   /**
    * @see Value::getFloat()
    */
    public function getFloat()
    {
        $this->setValueConsumed();
        
        if (!is_null($this->data)) {
            switch (gettype($this->data)) {
            case 'array' :
            case 'object' :
                phpCR::loadException('ValueFormat');
                throw new ValueFormatException('conversion to float failed');
                break;
            
            default :
                return floatval($this->data);
                break;
            }
        } else {
            phpCR::loadException('ValueFormat');
            throw new ValueFormatException('empty value');
        }
    }
    
    
   /**
    * @see Value::getString()
    */
    public function getString() 
    {
        $this->setValueConsumed();
        
        if (!is_null($this->data)) {
            switch (gettype($this->data)) {
            case 'array' :
            case 'object' :
                phpCR::loadException('ValueFormat');
                throw new ValueFormatException('conversion to string failed');
                break;
            
            default :
                return strval($this->data);
                break;
            }
            
        } else {
            phpCR::loadException('ValueFormat');
            throw new ValueFormatException('empty value');
        }
    }
    
    
   /**
    * @see Value::getBoolean()
    */
    public function getBoolean()
    {
        $this->setValueConsumed();
        
        if (!is_null($this->data)) {
            return (boolean)$this->getData();
        } else {
            phpCR::loadException('ValueFormat');
            throw new ValueFormatException('empty value');
        }
    }
    
    
   /**
    * @see Value::getStream(), ValueStream
    */
    public function getStream()
    {
        $this->setStreamConsumed();

        if ($this->stream != null) {
            return $this->stream;
        }
        
        $registry = ValueStreamRegistry::getInstance();
        $stream = fopen('Value://' . $registry->count(), 'r+');
        
        fwrite($stream, $this->getString());
        return $stream;
    }
}

